#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <net/route.h>  
#include <signal.h>
#include <ctype.h>
#include <sys/epoll.h>
#include<stdio.h>
#include <pthread.h>


#define 		__FILENAME__ (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1):__FILE__)
#define			PENDING_QUEUE                           20
#define 		DATA_BUF 								1024*4

#define logINO(format,...) printf("\033[01;30m %s %s.%d: " format " \033[0m \n", __FILENAME__,__FUNCTION__,__LINE__, ##__VA_ARGS__)
#define logBLUE(format,...) printf("\033[01;34m %s %s.%d: " format " \033[0m \n", __FILENAME__,__FUNCTION__,__LINE__, ##__VA_ARGS__)
#define logYELL(format,...) printf("\033[01;33m %s %s.%d: " format " \033[0m \n", __FILENAME__,__FUNCTION__,__LINE__, ##__VA_ARGS__)
#define logPURP(format,...) printf("\033[01;35m %s %s.%d: " format " \033[0m \n", __FILENAME__,__FUNCTION__,__LINE__, ##__VA_ARGS__)
#define logRED(format,...) printf("\033[01;31m %s %s.%d: " format " \033[0m \n", __FILENAME__,__FUNCTION__,__LINE__, ##__VA_ARGS__)
#define logWHI(format,...) printf("\033[04;37m %s %s.%d: " format " \033[0m \n", __FILENAME__,__FUNCTION__,__LINE__, ##__VA_ARGS__)
#define logGRE(format,...) printf("\033[04;32m %s %s.%d: " format " \033[0m \n", __FILENAME__,__FUNCTION__,__LINE__, ##__VA_ARGS__)
#define logDEE(format,...) printf("\033[01;36m %s %s.%d: " format " \033[0m \n", __FILENAME__,__FUNCTION__,__LINE__, ##__VA_ARGS__)

#define IP_LEN 						20
#define FD_CNT						64
int netInfo[FD_CNT][2] = {0};

int createTcpSvr()
{
    logINO("ql_socket_service_create--");
    int ql_socket_id = 0;
    char ret = 0;
    int sk_port = 1111;

    /**************creat socket handle**********/
    if((ql_socket_id = socket(AF_INET,SOCK_STREAM,0)) < 0){
        perror("socket");
        return -1;
    }
    /**********************set socket addr reuse**********************/    
    int reuseaddr = 1;
    if(setsockopt(ql_socket_id, SOL_SOCKET, SO_REUSEADDR,(const void *)&reuseaddr,(socklen_t)sizeof(int)) == -1){
         perror("setsockopt\n");
         logRED("setsockopt----errno[%d]",errno);
         return -1;
    }else{
        printf("setsockopt\n");
    }

    /********************set socket property*************************/
    struct sockaddr_in service_addr;
    bzero(&service_addr,sizeof(service_addr));
    service_addr.sin_family=AF_INET;
    service_addr.sin_port=htons(sk_port);
    service_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    /**********************bind socket addr and port**********************/
    if (bind(ql_socket_id,(struct sockaddr *)&service_addr,sizeof(struct sockaddr)) == -1){
        perror("bind");
        return -1;
    }else{
        logGRE("bind success--sk_port[%d]",sk_port);
    }
    if(listen(ql_socket_id, PENDING_QUEUE) == -1){
        perror("listen");
        return -1;
    }else{
        logGRE("listen success");
    }    
    return ql_socket_id;
}

void ParsrPorchLightMode(char* inputStr)
{
	logWHI("ParsrPorchLightMode [%s]",inputStr);
	if(netInfo[1][1]){
		send(netInfo[1][0],inputStr,1,0);
	}
}
void server_operate_cmd(void* buff)
{
	logWHI("server_operate_cmd");
	char inputStr[64] = {0};
	while(1){
		scanf("%s", inputStr);
		logWHI("inputStr [%s]",inputStr);
		ParsrPorchLightMode(data_buffer);
	}
}

int main(int argv,char** atgv)
{
	printf("my porch light\n");
	int svrfd = createTcpSvr();
	netInfo[0][0] = svrfd;
	netInfo[0][1] = 1;

	int maxFd = svrfd;
    fd_set client_rset;    
    fd_set client_wset;
    FD_ZERO(&client_rset);
    FD_ZERO(&client_wset);
    FD_SET(svrfd, &client_rset);
    FD_SET(svrfd, &client_wset);

    fd_set FdsTempR = client_rset;    
    fd_set FdsTempW = client_wset;

    struct timeval dl_tv = {15, 0}; //QL_GET_FILE_DELAY_TIME
    struct timeval tempo_tv ;    

    char data_buffer[DATA_BUF] = {0};
	int new_sk;
    struct sockaddr_in CliInfo;
    socklen_t CLiLen = sizeof(CliInfo);

    char       MyIP[20];     //不限制网卡，默认写 0.0.0.0
    int        MyPort;
	int			fdsFlag;
	int 		rec_len;

    pthread_attr_t attr;
	pthread_t subthid;
    int ret_a = pthread_attr_init(&attr );
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
    pthread_create(&subthid, &attr, (void*)server_operate_cmd, NULL);

	while(1){
        tempo_tv = dl_tv;
        FdsTempR = client_rset;    
        FdsTempW = client_wset;

        fdsFlag = select(maxFd+1,&FdsTempR,&FdsTempW,NULL,&tempo_tv);
        memset(data_buffer,0,DATA_BUF);
        switch(fdsFlag)
        {
        case -1:
            logPURP("error data len[%d]",fdsFlag);
            return -1;
        case 0:
            logPURP("time out ");
            break;
        default:
            if(FD_ISSET(netInfo[0][0],&FdsTempR)){
				logPURP(" there one client connected");
				new_sk = accept(netInfo[0][0] ,(struct sockaddr*)&CliInfo,&CLiLen);
				inet_ntop(AF_INET,&CliInfo.sin_addr,(char*)MyIP,IP_LEN);
				MyPort = ntohs(CliInfo.sin_port);
				logPURP(" there is a new client,fd[%d][%s][%d]",new_sk,MyIP,MyPort);
				for(int i = 0;i < FD_CNT;i++){
					if(netInfo[i][1] == 0){
						netInfo[i][0] = new_sk;
						netInfo[i][1] = 1;
						maxFd = new_sk > maxFd?new_sk:maxFd;
					    FD_SET(new_sk, &client_rset);
					    FD_SET(new_sk, &client_wset);

						break;
					}
				}
			}else{
				for(int i = 1;i < FD_CNT && netInfo[i][1];i++){
					if(FD_ISSET(netInfo[i][0],&FdsTempR)){
		                rec_len = recv(netInfo[i][0],data_buffer,DATA_BUF,0);
		                switch (rec_len)
		                {
		                case -1:
		                     logPURP(" error[%s]errno[%d]",strerror(errno),errno);                    
		                     return -1;
		                 case 0:
						 	netInfo[i][1] = 0;
							FD_CLR(netInfo[i][0], &FdsTempR);    
							FD_CLR(netInfo[i][0], &FdsTempW);    
		                    logPURP("client socket diconnect!!!sk[%d]",netInfo[i][0]);
		                    break;
		                default:
		                    logPURP("rec_len [%d]data_buffer[%s]",rec_len,data_buffer);
		                    break;
		                }
					}
		        }
			}
		}
	}
	return 0;
}